#ifndef LISTA_H
#define LISTA_H

#include <stdbool.h>
#include <stddef.h>

/* ******************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS
 * *****************************************************************/

/* La lista está planteada como una lista de punteros genéricos. */

typedef struct lista lista_t;
typedef struct iterador lista_iter_t;

/* ******************************************************************
 *                    PRIMITIVAS DE LA LISTA
 * *****************************************************************/
 
                       /*Primitivas básicas*/
// Crea una lista.
// Post: devuelve una nueva lista vacía.
lista_t *lista_crear();

// Devuelve verdadero o falso, según si la lista tiene o no elementos.
// Pre: la lista fue creada.
bool lista_esta_vacia(const lista_t *lista);

// Agrega un nuevo elemento a la lista en la primera posicion. Devuelve falso en caso
// de error.
// Pre: la lista fue creada.
// Post: se agregó un nuevo elemento a la lista, el elemento se encuentra en la primera 
//posicion.
bool lista_insertar_primero(lista_t *lista, void *dato);

// Agrega un nuevo elemento a la lista en la ultima posicion. Devuelve falso en caso de error.
// Pre: la lista fue creada.
// Post: se agregó un nuevo elemento a la lista, el elemento se encuentra en la ultima
// posicion.
bool lista_insertar_ultimo(lista_t *lista, void *dato);

// Saca el primer elemeto de la lista. Si la lista tiene elementos, se quita el
// primero, y se devuelve ese valor. Si la lista está vacía, devuelve NULL.
// Pre: la lista fue creada.
// Post: si la lista no estaba vacía, se devuelve el valor del primer elemento 
// y la lista contiene un elemento menos.
void *lista_borrar_primero(lista_t *lista);

// Obtiene el valor del primer elemento de la lista. Si la lista tiene
// elementos, se devuelve el valor del primero, si está vacía devuelve NULL.
// Pre: la lista fue creada.
// Post: se devolvió el primer elemento de la lista, cuando no está vacía.
void *lista_ver_primero(const lista_t *lista);

// Devuelve el largo de la lista.
// Pre: la lista fue creada.
size_t lista_largo(const lista_t *lista);

// Destruye la lista. Si se recibe la función destruir_dato por parámetro,
// para cada uno de los elementos de la lista llama a destruir_dato.
// Pre: la lista fue creada. destruir_dato es una función capaz de destruir
// los datos de la lista, o NULL en caso de que no se la utilice.
// Post: se eliminaron todos los elementos de la lista.
void lista_destruir(lista_t *lista, void destruir_dato(void *));

                        /*Primitivas de iteración*/
                        
// Crea un iterador.
// Pre: La lista fue creada. 
// Post: devuelve un iterador, apuntando a primer elemento de la lista.
lista_iter_t *lista_iter_crear(const lista_t *lista);

// Avanza el iterador al siguiente elemento de la lista. En caso de error devuelve false.
// Pre: el iterador y la lista fueron creados.
// Post: devuelve un booleano si pudo o no avanzar el iterador.
bool lista_iter_avanzar(lista_iter_t *iter);

// Devuelve el dato al que esta apuntando el iterador. Si el iterador esta en el final de la
// lista devuelve NULL.
// Pre: el iterador y la lista fueron creados.
// Post: Devuelve el dato al que apuntaba el iterador o NULL.
void *lista_iter_ver_actual(const lista_iter_t *iter);

// Devuelve true o false si el iterador se encuantra al final o no de la lista.
// Pre: el iterador y la lista fueron creados.
// Post: devuelve un booleano segun donde apunte el iterador.
bool lista_iter_al_final(const lista_iter_t *iter);

// Destruye el iterador.
// Pre: el iterador fue creado.
void lista_iter_destruir(lista_iter_t *iter);

                        /*Primitivas de listas junto con iterador*/
                        
// Devulve true si pudo insertar el elemento en la lista, false en caso de error.
// El elemento es insertado en la posicion anterior a lo apuntado por el iterador.
// El iterador queda apuntando a este nuevo elemento.
// Pre: el iterador y la lista fueron creados.
// Post: devuelve un booleano segun si pudo insertar o no el elemento, y la lista
// modificada con un elemento mas.
bool lista_insertar(lista_t *lista, lista_iter_t *iter, void *dato);

// Devuelve el dato del elemento que se borro, o NULL en caso de error.
// El iterador que apuntado al siguiente elemento del borrado.
// Pre: la lista y el iterador fueron creados.
// Post: devuelve el dato que contenia el elemento que se borro de la lista y la lista
// modificada con un elemento menos.
void *lista_borrar(lista_t *lista, lista_iter_t *iter);

#endif // LISTA_H


